package org.syncsoft.overalt.core.api;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.syncsoft.overalt.common.api.ApplicationUser;
import org.syncsoft.overalt.common.api.Configuration;
import org.syncsoft.overalt.common.api.IObserver;
import org.syncsoft.overalt.common.exception.SystemException;
import org.syncsoft.overalt.common.util.FileUtils;
import org.syncsoft.overalt.communication.api.Communication;
import org.syncsoft.overalt.communication.api.ICommunication;
import org.syncsoft.overalt.communication.exception.LoginException;
import org.syncsoft.overalt.core.util.XMLConfCore;
import org.syncsoft.overalt.core.util.XMLCore;
import org.syncsoft.overalt.domain.community.entity.Community;
import org.syncsoft.overalt.domain.document.entity.Document;
import org.syncsoft.overalt.domain.document.entity.Permission;
import org.syncsoft.overalt.domain.document.entity.Policy;
import org.syncsoft.overalt.domain.folder.entity.TypeShare;
import org.syncsoft.overalt.domain.folder.entity.TypeSyncronization;
import org.syncsoft.overalt.domain.tag.entity.Tag;
import org.syncsoft.overalt.domain.user.entity.User;

/**
 * concrete class that implements ICore
 * it's implements the singleton pattern
 * 
 * @author 
 *
 */
public final class Core implements ICore {
	private final static Core instance;
	private Collection<IObserver> observers;
	
	static {
		instance = new Core();
	}

	private Core() {
		setObservers(new HashSet<IObserver>());
	}

	/**
	 * @return a unique and valid instance of Core class
	 */
	public static Core getInstance() {
		return instance;
	}

	/*
	 * (non-Javadoc)
	 * @see org.syncsoft.common.api.ISubject#addObserver(org.syncsoft.common.api.IObserver)
	 */
	@Override
	public void addObserver(IObserver observer) {
		if (observer != null) {
			getObservers().add(observer);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.syncsoft.common.api.ISubject#remObserver(org.syncsoft.common.api.IObserver)
	 */
	@Override
	public void remObserver(IObserver observer) {
		if (observer != null) {
			getObservers().remove(observer);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.syncsoft.common.api.ISubject#notifyAllObservers()
	 */
	@Override
	public void notifyAllObservers() {
		for (IObserver observer: getObservers()) {
			observer.update();
		}
	}
	/**
	 * @param path path of the file 
	 * @author plrj
	 * @throws Exception 
	 */
	
	public void update(String filePath) throws SystemException {
		validateFilePath(filePath);
		
		File file = new File(filePath);
		int fileID = XMLCore.getInstance().getFileId(file.getParent(), filePath);
		//int fileVersion = XMLCore.getInstance().getFileVersion(file.getParent(), filePath);
		Document fileOnServer = getCommunication().getDocument(fileID);
		
		if(verifyFileOnFolder(file.getParent(), fileOnServer)) {
			//if(fileOnServer.getVersion() > fileVersion) {
				Collection<Integer> fileData = getCommunication().getDocumentFile(fileID);
				FileUtils.writeFile(filePath, fileData);
		
				setFileConfiguration(file.getParent(), filePath, fileID, fileOnServer.getTitle(), fileOnServer.getDescription(), fileOnServer.getCommunities(), fileOnServer.getTags(), fileOnServer.getPolicy().getPermission(), new Date());
			//}
			
		} else {
			deleteLocal(filePath);
		}	
	}
	
	
	private void update(String filePath, Document fileOnServer) throws SystemException {
		validateFilePath(filePath);
		
		File file = new File(filePath);
		int fileID = XMLCore.getInstance().getFileId(file.getParent(), filePath);
		
		// TODO fileVersion
//		int fileVersion = XMLCore.getInstance().getFileVersion(file.getParent(), filePath);
		
		if(verifyFileOnFolder(file.getParent(), fileOnServer)) {
			//if(fileOnServer.getVersion() > fileVersion) {
				Collection<Integer> fileData = getCommunication().getDocumentFile(fileID);
				FileUtils.writeFile(filePath, fileData);
				
				setFileConfiguration(file.getParent(), filePath, fileID, fileOnServer.getTitle(), fileOnServer.getDescription(), fileOnServer.getCommunities(), fileOnServer.getTags(), fileOnServer.getPolicy().getPermission(), new Date());
			//}
		} else {
			deleteLocal(filePath);
		}
	}
	
	private void createNewFile(String folderPath, int fileOnServerID) throws SystemException {
		validateFolderPath(folderPath);
		
		Document fileOnServer = getCommunication().getDocument(fileOnServerID);
		String newFilePath = folderPath + fileOnServer.getFileName();
		Collection<Integer> fileData = getCommunication().getDocumentFile(fileOnServer.getCode());
		FileUtils.writeFile(folderPath, fileData);
		
		boolean commitable = false;
		if(getUserCode() == fileOnServer.getUser().getCode()) {
			commitable = true;
		}
	
		XMLCore.getInstance().insertFile(folderPath, newFilePath, String.valueOf(fileOnServer.getCode()), commitable);
		setFileConfiguration(folderPath, newFilePath, fileOnServer.getCode(), fileOnServer.getTitle(), fileOnServer.getDescription(), fileOnServer.getCommunities(), fileOnServer.getTags(), fileOnServer.getPolicy().getPermission(), new Date());

	}
	
	private void validateFilePath(String filePath) throws SystemException {
		if(filePath == null) {
			throw new SystemException("Invalid file path");
		} else {
			File file = new File(filePath);
			if(!file.exists()) {
				throw new SystemException("This file not exists");
			} else if (!file.isFile()) {
				throw new SystemException("This path is not a file");
			}
		}
	}
	
	private void validateFolderPath(String folderPath) throws SystemException {
		if(folderPath == null) {
			throw new SystemException("Invalid folder path");
		} else {
			File file = new File(folderPath);
			if(!file.exists()) {
				throw new SystemException("This folder not exists");
			} else if (!file.isDirectory()) {
				throw new SystemException("This path is not a folder");
			}
		}
	}
	
	private void setFileConfiguration(String folderPath, String filePath, int fileID, String title, String description, Set<Community> communities, Set<Tag> tags, Permission permission, Date lastModified) throws SystemException {
		validateFolderPath(folderPath);
		validateFilePath(filePath);
		
		String fileIDStr = String.valueOf(fileID);
		Set<String> commsIds = null;
		if(communities!= null & communities.size() > 0) {
			commsIds = new HashSet<String>();
			for(Community c: communities) {
				commsIds.add(String.valueOf(c.getCode()));
			}
			XMLConfCore.getInstance().setFileCommunities(commsIds, fileIDStr);
		}
		Set<String> tagsStr = null;
		if(tags != null && tags.size() > 0) {
			tagsStr = new HashSet<String>();
			for(Tag tag: tags) {
				tagsStr.add(tag.getDescription());
			}
			XMLConfCore.getInstance().setFileTags(tagsStr, fileIDStr);
		}
		//XMLCore.getInstance().setFileVersion(folderPath, filePath, String.valueOf(version));
		XMLConfCore.getInstance().setFilePermission(String.valueOf(permission.ordinal()), fileIDStr);
		XMLConfCore.getInstance().setFileTitle(fileIDStr, title);
		XMLConfCore.getInstance().setFileDescription(fileIDStr, description);
		XMLConfCore.getInstance().setLastModified(fileIDStr, String.valueOf(lastModified.getTime()));
	}
	
	
	/**
	 * @param path path of the file
	 * @param title title of the file
	 * @param description description of the file
	 * @author plrj
	 * @throws SystemException 
	 */
	
	public void addFile(String filePath, String title, String description, Set<Community> communities, Set<Tag> tags, Permission permission) throws SystemException {
		validateFilePath(filePath);
		
		File file = new File(filePath);
		Document document = new Document();
		document.setTitle(title);
		document.setDescription(description);
		document.setFilepath(filePath);		
		document.setCommunities(communities);
		document.setTags(tags);
		
		Policy policy = new Policy();
		policy.setPermission(permission);
		document.setPolicy(policy);
		
		User user = new User();
		user.setCode(getUserCode());
		document.setUser(user);
		
		int fileId = getCommunication().addFile(document, file);
		
		if (fileId > -1) {
			Document fileOnServer = getCommunication().getDocument(fileId);
			//XMLCore.getInstance().insertFile(new File(filePath).getParent(), filePath, String.valueOf(fileId), true, String.valueOf(fileOnServer.getVersion()));
			XMLCore.getInstance().insertFile(new File(filePath).getParent(),
					filePath, String.valueOf(fileId), true);
			XMLConfCore.getInstance().setLastModified(String.valueOf(fileId),
					String.valueOf(new Date().getTime()));
			setFileConfiguration(file.getParent(), filePath, fileId, fileOnServer.getTitle(), fileOnServer.getDescription(), fileOnServer.getCommunities(), fileOnServer.getTags(), fileOnServer.getPolicy().getPermission(), new Date());
		}
	}
	
	/**
	 * @param path path of the file
	 * @param description description of this commit
	 * @author plrj
	 * @throws IOException 
	 */	
	
	public void commit(String filePath, String title, String description, String versionDescription ,Set<Community> communities, Permission permission, Set<Tag> tags) throws SystemException {
		verifyLogin();
		validateFilePath(filePath);
		
		File file = new File(filePath);
		int fileId = XMLCore.getInstance().getFileId(file.getParent(), filePath);
		
		Document document = new Document();
		document.setCode(fileId);
		document.setTitle(title);
		document.setDescription(description);
		document.setFilepath(filePath);		
		document.setCommunities(communities);
		document.setTags(tags);
		
		Policy policy = new Policy();
		policy.setPermission(permission);
		document.setPolicy(policy);
		
		getCommunication().commit(versionDescription, document, file);
		Document fileOnServer = getCommunication().getDocument(document.getCode());
		
		//XMLCore.getInstance().setFileVersion(file.getParent(), filePath, String.valueOf(fileOnServer.getCode()));
		XMLConfCore.getInstance().setLastModified(String.valueOf(fileId), String.valueOf(new Date().getTime()));
		setFileConfiguration(file.getParent(), filePath, fileId, fileOnServer.getTitle(), fileOnServer.getDescription(), fileOnServer.getCommunities(), fileOnServer.getTags(), fileOnServer.getPolicy().getPermission(), new Date());
	}
	
	public void commit(Collection<String> filesPaths, String versionDescription) throws SystemException {
		verifyLogin();
		
		if (filesPaths != null) {
			for(String filePath: filesPaths) {
				validateFilePath(filePath);
				
				File file = new File(filePath);
				int fileId = XMLCore.getInstance().getFileId(file.getParent(), filePath);
				Document document = getCommunication().getDocument(fileId);
				getCommunication().commit(versionDescription, document, file);
				//XMLCore.getInstance().setFileVersion(file.getParent(), filePath, String.valueOf(version));
				XMLConfCore.getInstance().setLastModified(String.valueOf(fileId), String.valueOf(new Date().getTime()));
			}
		}
	}
	
	public void updateFolderFiles(String folderPath) throws SystemException {
		validateFolderPath(folderPath);
		
		Collection<Document> filesOnServer = getFolderFilesOnServer(folderPath);
		
		for(Document fileOnServer: filesOnServer) {
			String filePath = XMLCore.getInstance().getFilepathByFileId(folderPath, String.valueOf(fileOnServer.getCode()));
			if(filePath == null) {
				createNewFile(folderPath, fileOnServer.getCode());				
			} else {
				update(filePath, fileOnServer);
			}
		}
		
		Collection<Document> files = XMLCore.getInstance().getFilesSharedByFolder(folderPath);
		for(Document doc: files) {
			if(!filesOnServer.contains(doc)) {
				delete(XMLCore.getInstance().getFilepathByFileId(folderPath, String.valueOf(doc.getCode())));
			}
		}
	}
	
	public void commitFolderFiles(String folderPath) throws SystemException {
		validateFolderPath(folderPath);
		
		File folder = new File(folderPath);
		File[] files = folder.listFiles();
				
		if(files != null && files.length > 0) {			
			for(File file: files) {
				
				int fileId = XMLCore.getInstance().getFileId(folderPath, file.getAbsolutePath());
				
				String title = FileUtils.getFileTitle(file.getAbsolutePath());
				String description = FileUtils.getFileDescription(file.getAbsolutePath());
				
				if(fileId == -1) {
					
					String community = XMLConfCore.getInstance().getFolderCommunityByFolderFilepath(folderPath);	
					
					Set<Community> comms = null;
					if(community != null) {
						comms = new HashSet<Community>();
						comms.add(new Community(Integer.valueOf(community)));
					}
					
					Collection<String> tagsString = XMLConfCore.getInstance().getFolderTags(folderPath);
					
					Set<Tag> tags = null;
					if(tagsString != null) {
						tags = new HashSet<Tag>();
						for(String tagDesc: tagsString) {
							tags.add(new Tag(tagDesc));
						}
					}
					
					Permission permission = Permission.getPermission(Integer.parseInt(XMLConfCore.getInstance().getDefaultPermission()));
					
					addFile(file.getAbsolutePath(), title, description, comms, tags, permission);
					
				} else {
					
					Long lastModified = Long.parseLong(XMLConfCore.getInstance().getLastModified(String.valueOf(fileId)));
					
					if(file.lastModified() > lastModified) {
						
						Permission permission = Permission.getPermission(XMLConfCore.getInstance().getFilePermission(String.valueOf(fileId)));						
						
						Collection<String> commsString = XMLConfCore.getInstance().getFileCommunities(String.valueOf(fileId));
						
						Set<Community> communities = null;
						for(String commId: commsString) {
							communities = new HashSet<Community>();
							communities.add(new Community(Integer.parseInt(commId)));
						}
						
						Collection<String> tagsString = XMLConfCore.getInstance().getFileTags(String.valueOf(fileId));
						
						Set<Tag> tags = null;
						for(String tagDesc: tagsString) {
							tags = new HashSet<Tag>();
							tags.add(new Tag(tagDesc));
						}
						
						commit(file.getAbsolutePath(), title, description, XMLConfCore.getInstance().getDefaultVersionDescription(), communities, permission, tags);
					}
					
				}
				
			}
		}
		
	}	
	
	private Collection<Document> getFolderFilesOnServer(String folderPath) throws SystemException {
		
		String indTypeShare = XMLConfCore.getInstance().getFolderTypeShare(folderPath);
		
		TypeShare typeShare = TypeShare.getTypeShare(Integer.valueOf(indTypeShare));
		
		Collection<Document> filesOnServer = null;
		
		if(typeShare == TypeShare.MY_FILES) {
			
			filesOnServer = getCommunication().getUserFiles(getUserCode());
			
		} else if(typeShare == TypeShare.CONTACTS_FILE) {
			
			Collection<String> contacts  = XMLConfCore.getInstance().getFolderContacts(folderPath);
			
			if(contacts != null && contacts.size() > 0) {
				for(String idContact: contacts) {
					filesOnServer = new ArrayList<Document>();
					filesOnServer.addAll(getCommunication().getUserFiles(Integer.parseInt(idContact)));
				}				
			}
			
		} else if(typeShare == TypeShare.COMMUNITY_FILES) {
			
			String idComm = XMLConfCore.getInstance().getFolderCommunityByFolderFilepath(folderPath);
			
			Collection<String> membersCommunity = XMLConfCore.getInstance().getFolderMembersCommunity(folderPath);
			
			Collection<Document> commFiles = getCommunication().getCommunityFiles(Integer.parseInt(idComm));
				
			if(membersCommunity != null && membersCommunity.size() > 0) {				
				
				for(Document commFile: commFiles) {
					if(membersCommunity.contains(String.valueOf(commFile.getUser().getCode()))) {
						filesOnServer = new ArrayList<Document>();
						filesOnServer.add(commFile);
					}
				}
			} else {
				filesOnServer = commFiles;
			}
			
		} else {
			throw new SystemException("Invalid Type Share");
		}
		
		return filesOnServer;
	}
	
	/**
	 * @param path path of the file
	 * @author plrj
	 * @throws Exception 
	 */
	
	public void delete(String filepath) throws SystemException {
		validateFilePath(filepath);
		File file = new File(filepath);
		getCommunication().delete(XMLCore.getInstance().getFileId(file.getParent(), file.getPath()));
		XMLCore.getInstance().removeFileByFilepath(file.getPath());
	}
	
	/**
	 * 
	 * @param filepath
	 * @throws SystemException
	 */
	public void deleteLocal(String filepath) throws SystemException {
		validateFilePath(filepath);
		File file = new File(filepath);
		XMLCore.getInstance().removeFileByFilepath(file.getPath());
		file.delete();
	}
	
	/**
	 * 
	 * @param folderPath path of the folder
	 * @author plrj
	 * @throws Exception 
	 */
	
	public void shareFolder(String folderPath, TypeShare typeShare, boolean autoFillTitleDesc, Set<Integer> contactsCode, Integer communityCode, Set<Integer> membersCode, boolean autoSync, TypeSyncronization typeSync, Set<Tag> tags) throws SystemException {
		validateFolderPath(folderPath);
		List<String> contactsIds = new ArrayList<String>();
		if(contactsCode != null) {
			for(Integer contactCode: contactsCode) {
				contactsIds.add(String.valueOf(contactCode));
			}
		}
		List<String> membersIds = new ArrayList<String>();
		if(membersCode != null) {
			for(Integer code: membersCode) {
				membersIds.add(String.valueOf(code));
			}
		}
		
		List<String> tagsStr = null;
		if(tags != null && tags.size() > 0) {
			for(Tag tag: tags) {
				if(tagsStr == null) {
					tagsStr = new ArrayList<String>();
				}
				tagsStr.add(tag.getDescription());
			}
		}
		
		XMLCore.getInstance().insertFolder(folderPath);
		try {
			XMLConfCore.getInstance().setFolderTypeShare(folderPath, String.valueOf(typeShare.ordinal()));
			XMLConfCore.getInstance().setFolderAutoTitleDescription(folderPath, autoFillTitleDesc);
			XMLConfCore.getInstance().addFolderContacts(folderPath, contactsIds);
			if(communityCode != null) {
				XMLConfCore.getInstance().setFolderCommunity(folderPath, String.valueOf(communityCode));
			}
			if(tags != null) {
				XMLConfCore.getInstance().addFolderTags(folderPath, tagsStr);
			}
			XMLConfCore.getInstance().setFolderMembersCommunity(folderPath, membersIds);
			if(autoSync){
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, String.valueOf(typeSync.ordinal()));
			}else{
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, "");
			}
			
		} catch (SystemException e) {	
			XMLCore.getInstance().removeFolder(folderPath);
		}

	}
	
	
	public void shareFolderMyFiles(String folderPath, boolean autoFillTitleDesc, boolean autoSync, TypeSyncronization typeSync, Set<Tag> tags) throws SystemException {
		validateFolderPath(folderPath);
		TypeShare typeShare = TypeShare.MY_FILES;
		List<String> tagsStr = null;
		if(tags != null && tags.size() > 0) {
			for(Tag tag: tags) {
				if(tagsStr == null) {
					tagsStr = new ArrayList<String>();
				}
				tagsStr.add(tag.getDescription());
			}
		}
		XMLCore.getInstance().insertFolder(folderPath);
		try {
			XMLConfCore.getInstance().setFolderTypeShare(folderPath, String.valueOf(typeShare.ordinal()));
			XMLConfCore.getInstance().setFolderAutoTitleDescription(folderPath, autoFillTitleDesc);
			if(tags != null) {
				XMLConfCore.getInstance().addFolderTags(folderPath, tagsStr);
			}
			if(autoSync){
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, String.valueOf(typeSync.ordinal()));
			}else{
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, "");
			}
			
		} catch (SystemException e) {	
			XMLCore.getInstance().removeFolder(folderPath);
		}		
	}
	
	public void shareFolderContactFiles(String folderPath, Set<Integer> contactsCode, boolean autoSync, TypeSyncronization typeSync, Set<Tag> tags) throws SystemException {
		validateFolderPath(folderPath);
		TypeShare typeShare = TypeShare.CONTACTS_FILE;
		List<String> tagsStr = null;
		if(tags != null && tags.size() > 0) {
			for(Tag tag: tags) {
				if(tagsStr == null) {
					tagsStr = new ArrayList<String>();
				}
				tagsStr.add(tag.getDescription());
			}
		}
		List<String> contactsIds = new ArrayList<String>();
		if(contactsCode != null) {
			for(Integer contactCode: contactsCode) {
				contactsIds.add(String.valueOf(contactCode));
			}
		}		
		XMLCore.getInstance().insertFolder(folderPath);
		try {
			XMLConfCore.getInstance().setFolderTypeShare(folderPath, String.valueOf(typeShare.ordinal()));
			XMLConfCore.getInstance().addFolderContacts(folderPath, contactsIds);
			if(tags != null) {
				XMLConfCore.getInstance().addFolderTags(folderPath, tagsStr);
			}
			if(autoSync){
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, String.valueOf(typeSync.ordinal()));
			}else{
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, "");
			}
			
		} catch (SystemException e) {	
			XMLCore.getInstance().removeFolder(folderPath);
		}		
	}
	
	public void shareFolderCommunityFiles(String folderPath, Integer communityCode, Set<Integer> membersCode, boolean autoSync, TypeSyncronization typeSync, Set<Tag> tags) throws SystemException {
		validateFolderPath(folderPath);
		TypeShare typeShare = TypeShare.COMMUNITY_FILES;
		List<String> tagsStr = null;
		if(tags != null && tags.size() > 0) {
			for(Tag tag: tags) {
				if(tagsStr == null) {
					tagsStr = new ArrayList<String>();
				}
				tagsStr.add(tag.getDescription());
			}
		}
		List<String> membersIds = new ArrayList<String>();
		if(membersCode != null) {
			for(Integer code: membersCode) {
				membersIds.add(String.valueOf(code));
			}
		}		
		XMLCore.getInstance().insertFolder(folderPath);
		try {
			XMLConfCore.getInstance().setFolderTypeShare(folderPath, String.valueOf(typeShare.ordinal()));
			if(communityCode != null) {
				XMLConfCore.getInstance().setFolderCommunity(folderPath, String.valueOf(communityCode));
			}
			if(tags != null) {
				XMLConfCore.getInstance().addFolderTags(folderPath, tagsStr);
			}
			XMLConfCore.getInstance().setFolderMembersCommunity(folderPath, membersIds);
			if(autoSync){
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, String.valueOf(typeSync.ordinal()));
			}else{
				XMLConfCore.getInstance().setFolderAutomatic(folderPath, autoSync, "");
			}
			
		} catch (SystemException e) {	
			XMLCore.getInstance().removeFolder(folderPath);
		}		
	}	

	@Override
	public Collection<Community> getComunities() throws SystemException {
		try {
			return getCommunication().getUserCommunities(getUserCode());
		} catch (NumberFormatException e) {
			throw new SystemException("Invalid User");
		}	
	}

	private int getUserCode() {
		int code;
		
		try {
			code = Configuration.getUserInSession().getCode();
		} catch (Exception e) {
			throw new LoginException();
		}
		
		return code;
	}
	
	@Override
	public Collection<User> getContacts() throws SystemException {
		try {
			return getCommunication().getUserContacts(getUserCode());
		} catch (NumberFormatException e) {
			throw new SystemException("Invalid User");
		}
	}
	
	private boolean verifyFileOnFolder(String folderPath, Document fileOnServer) throws SystemException {
		
	    String typeShareInd = XMLConfCore.getInstance().getFolderTypeShare(folderPath);
	    
	    TypeShare typeShare = TypeShare.getTypeShare(Integer.parseInt(typeShareInd));
	    
	    if(typeShare == TypeShare.MY_FILES) {
	    	
	    	int userID = getUserCode();
	    	
	    	if(userID == fileOnServer.getUser().getCode()) {
	    		return true;
	    	}
	    	
	    } else if (typeShare == TypeShare.COMMUNITY_FILES) {
	    	
	    	String commIDStr = XMLConfCore.getInstance().getFolderCommunityByFolderFilepath(folderPath);
	    	
	    	int commID = Integer.parseInt(commIDStr);
	    	
		    if(fileOnServer.getCommunities() != null || fileOnServer.getCommunities().size() > 0) {
		    	if (fileOnServer.getCommunities().contains(new Community(commID))) {
		    		return true;
		    	}
		    } 
	    	
	    } else if(typeShare == TypeShare.CONTACTS_FILE) {
	    	
	    	Collection<String> contatcs = XMLConfCore.getInstance().getFolderContacts(folderPath);
	    	
	    	if(contatcs.contains(String.valueOf(fileOnServer.getUser().getCode()))) {
	    		return true;
	    	}
	    }
	    
		return false;
	}

	@Override
	public Collection<Document> getModifiedFiles(String folderPath) throws SystemException {
		Collection<Document> modifiedFiles = new ArrayList<Document>();
		modifiedFiles.addAll(getAddCommitModifiedFiles(folderPath));
		modifiedFiles.addAll(getUpdateModifiedFiles(folderPath));
		return modifiedFiles;
	}
	
	private Collection<Document> getAddCommitModifiedFiles(String folderPath) throws SystemException {
		Collection<Document> addCommitModifiedFiles = new ArrayList<Document>();
		File folder = new File(folderPath);
		File[] files = folder.listFiles();	
		
		if(files != null && files.length > 0) {			
			for(File file: files) {
				
				int fileId;				
				try {
					fileId = XMLCore.getInstance().getFileId(folderPath, file.getAbsolutePath());
				} catch(SystemException e) {
					fileId = 0;
				}
				
				if(fileId == 0) {
					Document document = new Document(file.getAbsolutePath(), true);
					addCommitModifiedFiles.add(document);
					
				} else {
					
					try {
						Long lastModified = Long.parseLong(XMLConfCore.getInstance().getLastModified(String.valueOf(fileId)));
						if(file.lastModified() > lastModified) {
							
							Document document = getCommunication().getDocument(fileId);
							addCommitModifiedFiles.add(document);
						}
					} catch (NumberFormatException e) {
						throw new SystemException("Error getting last time modified of file");
					}					
				}				
			}
		}
		return addCommitModifiedFiles;
		
	}
	
	private Collection<Document> getUpdateModifiedFiles(String folderPath) throws SystemException {
		Collection<Document> updateModifiedFiles = new ArrayList<Document>();
		Collection<Document> filesOnServer = getFolderFilesOnServer(folderPath);
		for(Document fileOnServer: filesOnServer) {
			int localVersion = XMLCore.getInstance().getFileVersion(folderPath, folderPath + fileOnServer.getFileName());
			if(fileOnServer.getVersion() > localVersion) {
				updateModifiedFiles.add(fileOnServer);
			}
		}
		return updateModifiedFiles;
	}
	
	@Override
	public boolean login(String login, String password) throws SystemException{
		boolean islogged = false;
		ApplicationUser applicationUser = new ApplicationUser();
		 applicationUser.setLogin(login);
		 applicationUser.setPassword(password);
		 Configuration.setUserInSession(applicationUser);
		 int userId = getCommunication().getUserInSessionCode();
		 if (userId > -1) {
			applicationUser.setCode(userId);
			XMLCore.getInstance().init();
			islogged = true;
		}
		 return islogged;
	}
	
	public void saveUserLoginPassword(String login, String password) {
		File file = new File(System.getProperty("user.home") + "\\" + "overalt.user");
		try {
			file.createNewFile();
			PrintWriter pw = new PrintWriter(file);
			pw.println("login:" + login);
			pw.println("password:" + password);
			pw.flush();
			pw.close();
		} catch (IOException e) {
			System.out.println("Error creating file");
		}
		
	}
	
	public String getUserLogin() throws SystemException {
		File file = new File(System.getProperty("user.home") + "\\" + "overalt.user");
		if(!file.exists()) {
			throw new SystemException("File not exists");
		}
		try {
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			while(br.ready()) {
				String linha = br.readLine();
				if(linha.indexOf("login:") > -1) {
					return linha.substring(linha.indexOf("login:") + 6,linha.length());
				}
			}
		} catch (FileNotFoundException e) {
			throw new SystemException("File not found");
		} catch (IOException e) {
			throw new SystemException("Error reading file");
		}
		return null;
	}
	
	public String getUserPassword() throws SystemException {
		File file = new File(System.getProperty("user.home") + "\\" + "overalt.user");
		if(!file.exists()) {
			throw new SystemException("File not exists");
		}
		try {
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			while(br.ready()) {
				String linha = br.readLine();
				if(linha.indexOf("password:") > -1) {
					return linha.substring(linha.indexOf("password:") + 9,linha.length());
				}
			}
		} catch (FileNotFoundException e) {
			throw new SystemException("File not found");
		} catch (IOException e) {
			throw new SystemException("Error reading file");
		}
		return null;
	}
	
	private ICommunication getCommunication() {
		return Communication.getInstance();
	}
	
	public void openComparator(String filepath1, String filepath2)
	throws SystemException {
		try{
			String mergeExecute = Configuration.getMergeExecutable();
			mergeExecute = mergeExecute.replace("%filePaht1", filepath1);
			mergeExecute = mergeExecute.replace("%filePath2", filepath2);
			
			Runtime.getRuntime().exec(mergeExecute);
		}catch (Exception e) {
			throw new SystemException("An error ocurred when trying to open merge application.");
		}
	}

	
	//	GETS AND SETS
	private Collection<IObserver> getObservers() {
		return observers;
	}
	
	private void setObservers(Collection<IObserver> observers) {
		this.observers = observers;
	}

	@Override
	public Collection<User> getCommunityMembers(int communityId)
			throws SystemException {
		return getCommunication().getCommunityMembers(communityId);
	}
	
	public Document getFileLocalDocument(String filePath) throws SystemException {
		XMLConfCore xmlConfCore = XMLConfCore.getInstance();
		
		File file = new File(filePath);
		
		int fileId = XMLCore.getInstance().getFileId(file.getParent(), filePath);
		String fileIdStr = String.valueOf(fileId);
		
		String title = xmlConfCore.getFileTitle(fileIdStr);
		String description = xmlConfCore.getFileDescription(fileIdStr);
		Permission permission = Permission.getPermission(xmlConfCore.getFilePermission(fileIdStr));
		
		Collection<String> commsStr = xmlConfCore.getFileCommunities(fileIdStr);
		Set<Community> comms = null;
		if(commsStr != null && commsStr.size() > 0) {
			comms = new HashSet<Community>();
			for(String idCom: commsStr) {
				comms.add(new Community(Integer.valueOf(idCom)));
			}
		}
		
		Collection<String> tagsStr = xmlConfCore.getFileTags(fileIdStr);
		Set<Tag> tags = null;
		if(tagsStr != null && tagsStr.size() > 0) {
			tags = new HashSet<Tag>();
			comms = new HashSet<Community>();
			for(String tagDesc: commsStr) {
				tags.add(new Tag(tagDesc));
			}
		}
		
		Document document = new Document();
		document.setFilepath(filePath);
		document.setCode(fileId);
		document.setTitle(title);
		document.setDescription(description);
		document.setPolicy(new Policy(permission));
		document.setCommunities(comms);
		document.setTags(tags);
		
		return document;
	}
	
	public int getFolderCommunityId(String folderPath) throws SystemException {
		String commStr = XMLConfCore.getInstance().getFolderCommunityByFolderFilepath(folderPath);
		if(commStr != null) {
			return Integer.parseInt(commStr);
		} else {
			return -1;
		}
	}
	
	public Set<User> getFolderContatcts(String folderPath) throws SystemException {
		Set<User> contacts = null;
		Collection<String> contactsStr = XMLConfCore.getInstance().getFolderContacts(folderPath);
		if(contactsStr != null && contactsStr.size() > 0) {
			for(String contactId: contactsStr) {
				if(contacts == null) {
					contacts = new HashSet<User>();
				}
				contacts.add(new User(Integer.valueOf(contactId)));
			}
		}
		return contacts;
	}
	
	public Set<User> getFolderMembersCommunity(String folderPath) throws SystemException {
		Set<User> members = null;
		Collection<String> contactsStr = XMLConfCore.getInstance().getFolderMembersCommunity(folderPath);
		if(contactsStr != null && contactsStr.size() > 0) {
			for(String contactId: contactsStr) {
				if(members == null) {
					members = new HashSet<User>();
				}
				members.add(new User(Integer.valueOf(contactId)));
			}
		}
		return members;
	}
	
	public Set<Tag> getFolderTags(String folderPath) throws SystemException {
		Set<Tag> tags = null;
		Collection<String> tagsStr = XMLConfCore.getInstance().getFolderTags(folderPath);
		if(tagsStr != null && tagsStr.size() > 0) {
			for(String tagDesc: tagsStr) {
				if(tags == null) {
					tags = new HashSet<Tag>();
				}
				tags.add(new Tag(tagDesc));
			}
		}
		return tags;
	}
	
	public boolean getFolderAutoFillTitleDescription(String folderPath) throws SystemException {
		return false;
	}
	
	public boolean getFolderAutoSync(String folderPath) throws SystemException {
		return false;
	}
	
	public TypeShare getFolderTypeShare(String folderPath) throws SystemException {
		TypeShare typeShare = null;
		int indTypeShre = Integer.valueOf(XMLConfCore.getInstance().getFolderTypeSyncronization(folderPath));
		if(indTypeShre != -1) {
			typeShare = TypeShare.getTypeShare(indTypeShre);
		}
		return typeShare;
	}
	
	public TypeSyncronization getFolderTypeSync(String folderPath) throws SystemException {
		TypeSyncronization typeSync = null;
		int indTypeSync = Integer.valueOf(XMLConfCore.getInstance().getFolderTypeSyncronization(folderPath));
		if(indTypeSync != -1) {
			typeSync = TypeSyncronization.getTypeSyncronization(indTypeSync);
		}
		return typeSync;
	}

	@Override
	public void verifyLogin() {
		try {
			if (Configuration.getUserInSession().getCode() == 0){
				throw new LoginException();
			}
		} catch (Exception e) {
			throw new LoginException();
		}
	}
	
	public boolean isAutoTitleDescription(String folderPath) throws SystemException {
		Collection<String> folders = XMLConfCore.getInstance().getFoldersAutoTitleDescription();
		if(folders != null && folders.contains(folderPath)) {
			return true;
		}
		return false;
	}
	
	public String getFileTitle(String filePath) throws SystemException {
		return FileUtils.getFileTitle(filePath);
	}
	
	public String getFileDescription(String filePath) throws SystemException {
		return FileUtils.getFileDescription(filePath);
	}	
}
